from concurrent.futures import ThreadPoolExecutor
from multiprocessing.pool import Pool
from clint.textui import progress
from helper import OcrHelper
import threading
import time
from model.base import *
import urllib.parse
import hashlib
import urllib.request
import re
import os
import json
import redis
# import scoket
import requests
from exception import *

main_key = os.getenv('QINIU_MAIN_KEY')
backup_key = os.getenv('QINIU_BACKUP_KEY')
gov_file_url = os.getenv('QINIU_BASE_URL')
cur_time = int(time.time())
expired_time = cur_time + os.getenv('QINIU_EXPIRE_TIME')
expired_time = str(hex(expired_time))[2:]

# print(expired_time)
def url_response(url, path='./'):
    file_name = getFilename(url)
    path = path + file_name
    r = requests.get(url, stream=True)
    
    if r.status_code == 200:
        with open(path, 'wb') as f:
            total_length = int(r.headers.get('content-length'))
            # 边下载边存，每次2391975B
            for chunk in progress.bar(r.iter_content(chunk_size=1024), expected_size=(total_length/1024) + 1):
                f.write(chunk)
            f.close()
        return path
    else:
        raise HttpError(r.text)

def getUrl(url, params):
    if '?' in url:
        url += '&'
    else:
        url += '?'
    for key, value in params.items():
        url += '{}={}&'.format(key, value)
    return url[:-1]

def getQiniuUrl(url):
    # 替换#为%23
    url = url.replace('#', '%23');
    parsed_url = urllib.parse.urlparse(url)
    path = parsed_url.path
    path = path.replace('%23', '#')
    encoded_path = urllib.parse.quote(path, safe='/')
    encoded_path = '/'+encoded_path.lstrip('/')
    new_str = main_key + encoded_path + expired_time
    
    md5 = hashlib.md5()
    md5.update(new_str.encode('utf-8'))
    sign = md5.hexdigest()

    new_url = getUrl(url, {'sign': sign, 't': expired_time})
    
    return gov_file_url + new_url.replace(path, encoded_path.lstrip('/'))

def getFilename(url):
    url = url.split('?')[0]
    filename = url.split('/')[-1]
    filename = urllib.parse.unquote(filename)
    return filename

def save_file(qiniu_url, path='./'):
    socket.setdefaulttimeout(30)
    print('[%s]下载中...'%qiniu_url)
    file_name = getFilename(qiniu_url)
    path = path + file_name
    # 判断路径是否存在
    if not os.path.exists(os.path.dirname(path)):
        # 创建目录
        os.makedirs(os.path.dirname(path))
    # 保存文件
    # with open(path, 'w') as f:
    #     f.write('hello world')
    urllib.request.urlretrieve(qiniu_url, path)
    print('[%s]下载完成'%qiniu_url)
    return path

def filter_empty(arr):
    return list(filter(lambda x:x and x.strip(), arr))

# 任务处理
def action(number):
    # pid = os.getpid()
    print('Sub-process(%d)'%number)

    pool = redis.ConnectionPool(host=os.getenv('REDIS_HOST'), password=os.getenv('REDIS_PASSWORD'), port=os.getenv('REDIS_PORT'), db=os.getenv('REDIS_DB'), decode_responses=True)
    Redis = redis.Redis(connection_pool=pool)
    ocr = OcrHelper()

    while True:
        print('Sub-process(%d) 开始处理...'%number)
        startTime = int(time.time()) # 开始时间
        try:
        
            an_att_id = Redis.lpop('waiting_parse_an_att_ids')
            if an_att_id is None:
                print('list is None, job end')
                break

            print('Sub-process(%d) 准备处理[%s]'%(number, an_att_id))
            anAtt = AnAtt.get(AnAtt.id == an_att_id)
            qiniu_url = getQiniuUrl(anAtt.att_path)
            file_path = url_response(qiniu_url, './temp/%d__'%anAtt.id)

            print('Sub-process(%d) 开始OCR...[%s]'%(number, an_att_id))
            ocr_res = ocr.handle(file_path)
            print('Sub-process(%d) OCR成功[%s]'%(number, an_att_id))
            anAtt.status = 2
            anAtt.content = json.dumps(filter_empty(ocr_res['result']), ensure_ascii=False)
            anAtt.remark = ''
            anAtt.save()
            os.remove(file_path)
            print("(%d)[%s]ok"%(number, an_att_id))

        except Exception as err:
            anAtt.status = 3
            anAtt.remark = err
            anAtt.save()
            print("(%d)[%d]error: %s"%(number, anAtt.id, err))

        except OcrError as err:
            anAtt.status = 4
            anAtt.remark = err
            anAtt.save()
            print("(%d)[%d]ocr error: %s"%(number, anAtt.id, err))

        except HttpError as err:
            anAtt.status = 5
            anAtt.remark = err
            anAtt.save()
            print("(%d)[%d]download err: %s"%(number, anAtt.id, err))

        except CustomError as err:
            anAtt.status = 6
            anAtt.remark = err
            anAtt.save()
            print("(%d)[%d]custom err: %s"%(number, anAtt.id, err))

        except TypeError as err:
            anAtt.status = 7
            anAtt.remark = err
            anAtt.save()
            print("(%d)[%d]type err: %s"%(number, anAtt.id, err))

        endTime = int(time.time()) # 结束时间
        cost_seconds = endTime - startTime
        print("cost time: %ds"%cost_seconds)

    return number

# action(1)

# url_response('https://govfile.jx160.cn/jx/2022/07/30/5017c84c-6364-4805-92a5-0d593d9dc24c/G009%E9%87%87%E8%B4%AD%E9%9C%80%E6%B1%82.pdf?sign=fd0a373149ec21c4fc53ff12cbcbf6bc&t=0x63fefe4d')
# 创建一个包含4条线程的线程池
# with ThreadPoolExecutor(max_workers=3) as pool:
#     # 使用线程执行map计算
#     # 后面元组有3个元素，因此程序启动3条线程来执行action函数
#     results = pool.map(action, (1, 2, 3, 4))
#     print('--------------')
#     for r in results:
#         print(r)

# res = getQiniuUrl('jx/2021/02/22/abc21613-124a-4185-8b66-3baf71cf213e/中标通知书.jpg')
# print(res)

# try:
#     res = url_response('https://govfile.jx160.cn/jx/2021/02/22/abc21613-124a-4185-8b66-3baf71cf213e/%E4%B8%AD%E6%A0%87%E9%80%9A%E7%9F%A5%E4%B9%A6.jpg?sign=cf4db67634d423da9d6f27f88ddb5f48&t=6401a35f')
#     print(res)
# except CustomError as e:
#     print(e)

if __name__ == '__main__':
    processes = 20
    start = time.time()
    # 维持执行的进程总数为processes
    pool = Pool(processes = processes)
    for i in range(processes):
        # msg = "hello Sub-process(%d)" %(i)
        pool.apply_async(action, (i, ))   
 
    print("Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~")

    pool.close()
    pool.join()

    end = time.time()
    print(end - start, 's')
    print("Sub-process(es) done.")